package org.ysling.litemall.wx.service;
// Copyright (c) [ysling] [927069313@qq.com]
// [litemall-plus] is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//             http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.

import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;
import org.ysling.litemall.core.express.service.ExpressService;

import org.ysling.litemall.core.notify.NotifyService;
import org.ysling.litemall.core.notify.NotifyType;
import org.ysling.litemall.core.service.*;
import org.ysling.litemall.core.system.SystemConfig;
import org.ysling.litemall.core.tasks.impl.OrderCommentTask;
import org.ysling.litemall.core.tasks.impl.OrderUnconfirmedTask;
import org.ysling.litemall.core.tasks.impl.OrderUnpaidTask;
import org.ysling.litemall.core.tasks.service.TaskService;
import org.ysling.litemall.core.utils.*;
import org.ysling.litemall.core.weixin.pay.WeixinPayCoreService;
import org.ysling.litemall.core.weixin.service.SubscribeMessageService;
import org.ysling.litemall.db.constant.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.ysling.litemall.db.domain.*;
import org.ysling.litemall.db.service.*;
import org.ysling.litemall.db.vomain.UserVo;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

import static org.ysling.litemall.wx.util.WxResponseCode.*;

/**
 * 订单服务
 *
 * <p>
 * 订单状态：
 * 101 订单生成，未支付；102，下单后未支付用户取消；103，下单后未支付超时系统自动取消
 * 201 支付完成，商家未发货；202，订单生产，已付款未发货，但是退款取消；
 * 301 商家发货，用户未确认；
 * 401 用户确认收货； 402 用户没有确认收货超过一定时间，系统自动确认收货；
 *
 * <p>
 * 用户操作：
 * 当101用户未付款时，此时用户可以进行的操作是取消订单，或者付款操作
 * 当201支付完成而商家未发货时，此时用户可以取消订单并申请退款
 * 当301商家已发货时，此时用户可以有确认收货的操作
 * 当401用户确认收货以后，此时用户可以进行的操作是删除订单，评价商品，申请售后，或者再次购买
 * 当402系统自动确认收货以后，此时用户可以删除订单，评价商品，申请售后，或者再次购买
 */
@Service
public class WxOrderService {
    private final Log logger = LogFactory.getLog(WxOrderService.class);

    @Autowired
    private LitemallUserService userService;
    @Autowired
    private LitemallOrderService orderService;
    @Autowired
    private LitemallBrandService brandService;
    @Autowired
    private LitemallOrderGoodsService orderGoodsService;
    @Autowired
    private LitemallAddressService addressService;
    @Autowired
    private SubscribeMessageService subscribeMessageService;
    @Autowired
    private LitemallCartService cartService;
    @Autowired
    private LitemallGoodsProductService productService;
    @Autowired
    private LitemallGoodsService goodsService;
    @Autowired
    private WeixinPayCoreService payCoreService;
    @Autowired
    private NotifyService notifyService;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private LitemallGrouponRulesService grouponRulesService;
    @Autowired
    private WxGrouponRuleService grouponRuleService;
    @Autowired
    private LitemallGrouponService grouponService;
    @Autowired
    private ExpressService expressService;
    @Autowired
    private LitemallCommentService commentService;
    @Autowired
    private LitemallCouponUserService couponUserService;
    @Autowired
    private CouponVerifyService couponVerifyService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private LitemallAftersaleService aftersaleService;
    @Autowired
    private OrderCoreService orderCoreService;
    @Autowired
    private NotifyCoreService notifyCoreService;
    @Autowired
    private LitemallRewardTaskService rewardTaskService;
    @Autowired
    private LitemallRewardService rewardService;
    @Autowired
    private WxRewardService wxRewardService;

    /**
     * 订单列表
     *
     * @param userId   用户ID
     * @param showType 订单信息：
     *                 0，全部订单；
     *                 1，待付款；
     *                 2，待发货；
     *                 3，待收货；
     *                 4，待评价。
     * @param page     分页页数
     * @param limit     分页大小
     * @return 订单列表
     */
    public Object list(Integer userId, Integer showType, Integer page, Integer limit, String sort, String order) {
        if (Objects.isNull(userId)) {
            return ResponseUtil.unlogin();
        }

        List<Short> orderStatus = OrderConstant.orderStatus(showType);
        List<LitemallOrder> orderList = orderService.queryByOrderStatus(userId, orderStatus, page, limit, sort, order);

        List<Map<String, Object>> orderVoList = new ArrayList<>(orderList.size());
        for (LitemallOrder o : orderList) {
            Map<String, Object> orderVo = new HashMap<>();
            orderVo.put("id", o.getId());
            orderVo.put("orderSn", o.getOrderSn());
            orderVo.put("actualPrice", o.getActualPrice());
            orderVo.put("orderStatusText", OrderConstant.orderStatusText(o));
            orderVo.put("handleOption", OrderConstant.build(o));
            orderVo.put("aftersaleStatus", o.getAftersaleStatus());

            LitemallGroupon groupon = grouponService.queryByOrderId(o.getId());
            orderVo.put("groupon", groupon);
            if (groupon != null) {
                orderVo.put("isGroupon", true);
                orderVo.put("grouponStatus", GrouponConstant.GrouponStatusText(groupon));
            } else {
                orderVo.put("isGroupon", false);
            }

            List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(o.getId());
            List<Map<String, Object>> orderGoodsVoList = new ArrayList<>(orderGoodsList.size());
            for (LitemallOrderGoods orderGoods : orderGoodsList) {
                Map<String, Object> orderGoodsVo = new HashMap<>();
                orderGoodsVo.put("id", orderGoods.getId());
                orderGoodsVo.put("goodsName", orderGoods.getGoodsName());
                orderGoodsVo.put("number", orderGoods.getNumber());
                orderGoodsVo.put("picUrl", orderGoods.getPicUrl());
                orderGoodsVo.put("specifications", orderGoods.getSpecifications());
                orderGoodsVo.put("price",orderGoods.getPrice());
                orderGoodsVoList.add(orderGoodsVo);
            }
            orderVo.put("goodsList", orderGoodsVoList);

            orderVoList.add(orderVo);
        }
        return ResponseUtil.okList(orderVoList, orderList);
    }


    /**
     * 订单详情
     *
     * @param userId  用户ID
     * @param orderId 订单ID
     * @return 订单详情
     */
    public Object detail(Integer userId, Integer orderId) {
        if (Objects.isNull(userId)) {
            return ResponseUtil.unlogin();
        }
        // 订单信息
        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            LitemallBrand brand = brandService.findByUserId(userId);
            if (brand == null){
                return ResponseUtil.fail(ORDER_UNKNOWN, "订单不存在");
            }
            order = orderService.findByBrandId(brand.getId() , orderId);
            if (order == null){
                return ResponseUtil.fail(ORDER_UNKNOWN, "订单不存在");
            }
        }

        Map<String, Object> orderVo = new HashMap<>();
        orderVo.put("id", order.getId());
        orderVo.put("userId", order.getUserId());
        orderVo.put("orderSn", order.getOrderSn());
        orderVo.put("message", order.getMessage());
        orderVo.put("addTime", order.getAddTime());
        orderVo.put("payTime", order.getPayTime());
        orderVo.put("consignee", order.getConsignee());
        orderVo.put("mobile", order.getMobile());
        orderVo.put("address", order.getAddress());
        orderVo.put("orderPrice", order.getOrderPrice());
        orderVo.put("goodsPrice", order.getGoodsPrice());
        orderVo.put("couponPrice", order.getCouponPrice());
        orderVo.put("grouponPrice", order.getGrouponPrice());
        orderVo.put("integralPrice", order.getIntegralPrice());
        orderVo.put("freightPrice", order.getFreightPrice());
        orderVo.put("actualPrice", order.getActualPrice());
        orderVo.put("orderStatusText", OrderConstant.orderStatusText(order));
        orderVo.put("handleOption", OrderConstant.build(order));
        orderVo.put("aftersaleStatus", order.getAftersaleStatus());
        orderVo.put("expCode", order.getShipChannel());
        orderVo.put("expName", expressService.getVendorName(order.getShipChannel()));
        orderVo.put("expNo", order.getShipSn());
        if (!Objects.equals(order.getShipChannel(),"ZS") && StringUtils.hasText(order.getShipSn())){
            orderVo.put("expSuccess" , true);
        }

        Map<String, Object> result = new HashMap<>();
        result.put("orderInfo", orderVo);
        result.put("orderGoods", orderGoodsService.queryByOid(order.getId()));

        LitemallGroupon groupon = grouponService.queryByOrderId(order.getId());
        if (groupon != null){
            LitemallGrouponRules rules = grouponRulesService.findById(groupon.getRulesId());

            // 获取团购加入id
            Integer grouponId = groupon.getGrouponId();
            int linkGrouponId = grouponId == 0? groupon.getId(): groupon.getGrouponId();

            //参与记录
            UserVo creator = userService.findUserVoById(groupon.getCreatorUserId());
            List<UserVo> joiners = new ArrayList<>();
            joiners.add(creator);
            List<LitemallGroupon> grouponList = grouponService.queryJoinRecord(linkGrouponId);
            for (LitemallGroupon grouponItem : grouponList) {
                joiners.add(userService.findUserVoById(grouponItem.getUserId()));
            }

            result.put("linkGrouponId", linkGrouponId);
            result.put("creator", creator);
            result.put("joiners", joiners);
            result.put("groupon", groupon);
            result.put("rules", rules);
        }
        return ResponseUtil.ok(result);
    }

    /**
     * 提交订单
     * <p>
     * 1. 创建订单表项和订单商品表项;
     * 2. 购物车清空;
     * 3. 优惠券设置已用;
     * 4. 商品货品库存减少;
     * 5. 如果是团购商品，则创建团购活动表项。
     *
     * @param userId 用户ID
     * @param body   订单信息，{ cartId：xxx, addressId: xxx, couponId: xxx, message: xxx, grouponRulesId: xxx,  grouponLinkId: xxx}
     * @return 提交订单操作结果
     */
    public Object submit(Integer userId, String body) {
        if (Objects.isNull(userId)) {
            return ResponseUtil.unlogin();
        }
        if (body == null) {
            return ResponseUtil.badArgument();
        }
        Integer cartId = JacksonUtil.parseInteger(body, "cartId");
        String message = JacksonUtil.parseString(body, "message");
        Integer couponId = JacksonUtil.parseInteger(body, "couponId");
        Integer addressId = JacksonUtil.parseInteger(body, "addressId");
        Integer userCouponId = JacksonUtil.parseInteger(body, "userCouponId");
        Integer rewardLinkId = JacksonUtil.parseInteger(body, "rewardLinkId");
        Integer grouponLinkId = JacksonUtil.parseInteger(body, "grouponLinkId");
        Integer grouponRulesId = JacksonUtil.parseInteger(body, "grouponRulesId");


        //如果是团购项目,验证活动是否有效
        if (grouponRulesId != null && grouponRulesId > 0) {
            Object groupon = grouponRuleService.isGroupon(grouponRulesId, grouponLinkId, userId);
            if (groupon != null){
                return groupon;
            }
        }

        if (rewardLinkId != null && rewardLinkId > 0){
            LitemallReward reward = rewardService.findById(rewardLinkId);
            if (reward == null){
                return ResponseUtil.badArgument();
            }
            Object serviceReward = wxRewardService.isReward(reward.getTaskId());
            if (serviceReward != null){
                return serviceReward;
            }
        }

        if (cartId == null || addressId == null || couponId == null) {
            return ResponseUtil.badArgument();
        }

        // 收货地址
        LitemallAddress checkedAddress = addressService.query(userId, addressId);
        if (checkedAddress == null) {
            return ResponseUtil.badArgument();
        }

        // 团购优惠
        BigDecimal grouponPrice = new BigDecimal(0);
        LitemallGrouponRules grouponRules = grouponRulesService.findById(grouponRulesId);
        if (grouponRules != null) {
            grouponPrice = grouponRules.getDiscount();
        }

        // 货品信息
        List<LitemallCart> checkedGoodsList = null;
        if (cartId.equals(0)) {
            //获取购物车信息
            checkedGoodsList = cartService.queryByUidAndChecked(userId);
        } else {
            //获取购物车信息
            checkedGoodsList = new ArrayList<>(1);
            checkedGoodsList.add(cartService.findById(cartId));
        }

        if (checkedGoodsList == null || checkedGoodsList.size() <= 0) {
            return ResponseUtil.badArgumentValue();
        }


        BigDecimal checkedGoodsPrice = new BigDecimal(0);
        checkedGoodsPrice = LitemallCartService.getBigDecimal(grouponPrice, grouponRules, checkedGoodsList, checkedGoodsPrice);

        // 获取可用的优惠券信息,使用优惠券减免的金额
        BigDecimal couponPrice = new BigDecimal(0);
        // 如果couponId=0则没有优惠券，couponId=-1则不使用优惠券
        if (couponId != 0 && couponId != -1) {
            LitemallCoupon coupon = couponVerifyService.checkCoupon(userId, couponId, userCouponId, checkedGoodsPrice, checkedGoodsList);
            if (coupon == null) {
                return ResponseUtil.badArgumentValue();
            }
            couponPrice = coupon.getDiscount();
        }

        //订单总价
        BigDecimal allPrice = new BigDecimal(0);
        //保存订单id集合
        ArrayList<Integer> orderIds = new ArrayList<>();

        // 添加订单商品表项
        for (LitemallCart cartGoods : checkedGoodsList) {
            // 创建订单
            LitemallOrder order = new LitemallOrder();
            order.setUserId(userId);
            order.setMessage(message);
            order.setOrderStatus(OrderConstant.STATUS_CREATE);
            //订单编号
            order.setOrderSn(orderService.generateOrderSn(userId));
            //团购价格默认为零如果有团购直接相加
            order.setGrouponPrice(new BigDecimal(0).add(grouponPrice));
            //将优惠券金额分担给每件商品
            order.setCouponPrice(couponPrice.divide(BigDecimal.valueOf(checkedGoodsList.size())));

            //添加订单
            addOrderAndOrderGoods(cartGoods, order ,checkedAddress);
            //计算订单总金额
            allPrice = allPrice.add(order.getActualPrice());
            //将订单id加入集合返回出去
            orderIds.add(order.getId());

            // 商品货品数量减少
            Integer productId = cartGoods.getProductId();
            LitemallGoodsProduct product = productService.findById(productId);
            if (product.getNumber() < cartGoods.getNumber()) {
                throw new RuntimeException("库存不足");
            }
            if (productService.reduceStock(productId, cartGoods.getNumber()) <= 0) {
                throw new RuntimeException("库存减少失败");
            }

            //判断商品库存是否为0,如果是则下架商品
            if (productService.isGoodsNOStock(cartGoods.getGoodsId())){
                LitemallGoods litemallGoods = new LitemallGoods();
                litemallGoods.setId(cartGoods.getGoodsId());
                litemallGoods.setIsOnSale(false);
                if (goodsService.updateVersionSelective(litemallGoods) <= 0){
                    throw new RuntimeException("商品下架失败");
                }
            }

            // 删除购物车里面的商品信息
            if (cartService.deleteById(cartGoods.getId()) <= 0){
                throw new RuntimeException("购物车删除失败");
            }


            // 如果couponId=0则没有优惠券，couponId=-1则不使用优惠券
            if (couponId != 0 && couponId != -1) {
                // 如果使用了优惠券，设置优惠券使用状态
                LitemallCouponUser couponUser = couponUserService.findById(userCouponId);
                couponUser.setStatus(CouponUserConstant.STATUS_USED);
                couponUser.setUsedTime(LocalDateTime.now());
                couponUser.setOrderId(order.getId());
                if (couponUserService.updateVersionSelective(couponUser) == 0) {
                    throw new RuntimeException("优惠券使用失败");
                }
            }

            //添加赏金活动
            if (rewardLinkId != null && rewardLinkId > 0){
                LitemallReward reward = rewardService.findById(rewardLinkId);
                LitemallRewardTask rewardTask = rewardTaskService.findById(reward.getTaskId());
                LitemallReward newReward = new LitemallReward();
                newReward.setUserId(userId);
                newReward.setOrderId(order.getId());
                newReward.setRewardId(reward.getId());
                newReward.setTaskId(rewardTask.getId());
                newReward.setAward(rewardTask.getAward());
                newReward.setCreatorUserId(reward.getUserId());
                newReward.setStatus(RewardConstant.STATUS_NONE);
                rewardService.add(newReward);
            }

            //如果是团购项目，添加团购信息
            if (grouponRulesId != null && grouponRulesId > 0) {
                grouponLinkId = grouponRuleService.addGroupon(order.getId(), userId, grouponRulesId, grouponLinkId);
            }

            // NOTE: 建议开发者从业务场景核实下面代码，防止用户利用业务BUG使订单跳过支付环节。
            // 如果订单实际支付费用是0，则直接跳过支付变成待发货状态-----------单独
            if (order.getActualPrice().compareTo(BigDecimal.ZERO) <= 0 || !SystemConfig.isAutoPay()) {
                //有赏金更新赏金
                LitemallReward reward = rewardService.findByOrderId(order.getId());
                if (reward != null){
                    wxRewardService.updateRewardStatus(reward);
                }
                // 支付成功，有团购信息，更新团购信息
                LitemallGroupon groupon = grouponService.queryByOrderId(order.getId());
                if (groupon != null) {
                    orderCoreService.updateGrouponStatus(groupon);
                }else {
                    //跟新订单状态
                    order.setOrderStatus(OrderConstant.STATUS_BTL_PAY);
                    if (orderService.updateVersionSelective(order) == 0){
                        throw new RuntimeException("更新数据已失效");
                    }
                    //给商家发送邮件
                    notifyCoreService.orderNotify(order);
                }
            } else {
                // 订单支付超期任务
                taskService.addTask(new OrderUnpaidTask(order.getId()));
            }
        }

        Map<String, Object> data = new HashMap<>();
        data.put("isPay", allPrice.compareTo(BigDecimal.ZERO) <= 0 || !SystemConfig.isAutoPay());
        data.put("orderIds",orderIds);
        return ResponseUtil.ok(data);
    }


    /**
     * 添加订单信息和订单商品信息
     */
    private void addOrderAndOrderGoods(LitemallCart cartGoods, LitemallOrder order, LitemallAddress checkedAddress) {
        // 商品总价
        BigDecimal checkedGoodsPrice = cartGoods.getPrice().multiply(new BigDecimal(cartGoods.getNumber()));
        // 团购金额
        BigDecimal grouponPrice = order.getGrouponPrice().multiply(new BigDecimal(cartGoods.getNumber()));
        // 根据订单商品总价计算运费，满足条件（例如88元）则免运费，否则需要支付运费（例如8元）；
        BigDecimal freightPrice = new BigDecimal(0);
        if (checkedGoodsPrice.compareTo(SystemConfig.getFreightLimit()) < 0) {
            freightPrice = SystemConfig.getFreight();
        }
        BigDecimal couponPrice = order.getCouponPrice();
        // 最终支付费用
        BigDecimal actualPrice = checkedGoodsPrice
                .add(freightPrice)
                .subtract(grouponPrice)
                .subtract(couponPrice)
                .max(new BigDecimal(0));


        // 可以使用的其他钱，例如用户积分
        BigDecimal integralPrice = new BigDecimal(0);
        LitemallUser user = userService.findById(order.getUserId());
        if (user == null) throw new RuntimeException("用户不存在");

        if (!user.getUserLevel().equals(UserConstant.USER_LEVEL_0.status)){
            BigDecimal userIntegral = user.getIntegral();

            if (actualPrice.compareTo(userIntegral) >= 0){
                actualPrice = actualPrice.subtract(userIntegral);
                integralPrice = userIntegral;
                userIntegral = new BigDecimal(0);

            }else {
                userIntegral = userIntegral.subtract(actualPrice);
                integralPrice = actualPrice;
                actualPrice = new BigDecimal(0);
            }

            user.setIntegral(userIntegral);
            if (userService.updateVersionSelective(user) == 0){
                throw new RuntimeException("用户积分扣除失败");
            }
        }


        //详细地址
        String detailedAddress = checkedAddress.getProvince()
                +checkedAddress.getCity()
                +checkedAddress.getCounty()
                +checkedAddress.getAddressDetail();

        order.setBrandId(cartGoods.getBrandId());
        order.setAddress(detailedAddress);
        order.setMobile(checkedAddress.getTel());
        order.setConsignee(checkedAddress.getName());
        order.setGoodsPrice(checkedGoodsPrice);
        order.setFreightPrice(freightPrice);
        order.setIntegralPrice(integralPrice);
        order.setOrderPrice(actualPrice);
        order.setActualPrice(actualPrice);
        // 添加订单表项
        orderService.add(order);

        // 订单商品
        LitemallOrderGoods orderGoods = new LitemallOrderGoods();
        orderGoods.setOrderId(order.getId());
        orderGoods.setGoodsId(cartGoods.getGoodsId());
        orderGoods.setGoodsSn(cartGoods.getGoodsSn());
        orderGoods.setProductId(cartGoods.getProductId());
        orderGoods.setGoodsName(cartGoods.getGoodsName());
        orderGoods.setPicUrl(cartGoods.getPicUrl());
        orderGoods.setPrice(cartGoods.getPrice());
        orderGoods.setNumber(cartGoods.getNumber());
        orderGoods.setSpecifications(cartGoods.getSpecifications());
        orderGoods.setAddTime(LocalDateTime.now());
        orderGoodsService.add(orderGoods);
    }

    /**
     * 付款订单的预支付会话标识
     * <p>
     * 1. 检测当前订单是否能够付款
     * 2. 微信商户平台返回支付订单ID
     * 3. 设置订单付款状态
     *
     * @param userId 用户ID
     * @param body   订单信息，{ orderId：xxx }
     * @return 支付订单ID
     */
    public Object prepay(Integer userId, String body, HttpServletRequest request) {
        if (Objects.isNull(userId)) {
            return ResponseUtil.unlogin();
        }

        //订单支付总金额
        BigDecimal allPrice = new BigDecimal(0);
        //保存验证后的订单
        ArrayList<LitemallOrder> orders = new ArrayList<>();
        //获取订单id集合
        List<Integer> orderIds = JacksonUtil.parseIntegerList(body, "orderIds");

        if(orderIds ==null || orderIds.size() <= 0){
            return ResponseUtil.badArgument();
        }

        for (Integer orderId : orderIds) {
            if (orderId == null) {
                return ResponseUtil.badArgument();
            }

            //获取订单
            LitemallOrder order = orderService.findById(userId, orderId);
            if (order == null) {
                return ResponseUtil.badArgumentValue();
            }

            if (OrderConstant.isPayStatus(order) || OrderConstant.isBtlPayStatus(order)){
                continue;
            }

            //判断订单是否属于当前用户
            if (!order.getUserId().equals(userId)) {
                return ResponseUtil.badArgumentValue();
            }

            // 检测是否能够取消
            OrderHandleOption handleOption = OrderConstant.build(order);
            if (!handleOption.isPay()) {
                return ResponseUtil.fail(ORDER_INVALID_OPERATION, "订单不能支付");
            }

            orders.add(order);
            //订单金额相加
            allPrice = allPrice.add(order.getActualPrice());
        }

        //获取用户openid
        LitemallUser user = userService.findById(userId);
        String openid = user.getWeixinOpenid();
        if (openid == null) {
            return ResponseUtil.fail(AUTH_OPENID_UNACCESS, "订单不能支付");
        }

        WxPayMpOrderResult result = null;
        try {
            WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
            orderRequest.setOutTradeNo(orders.get(0).getOrderSn());
            orderRequest.setBody("order：" + orders.get(0).getOrderSn());
            orderRequest.setOpenid(openid);
            //将订单id集合传入微信支付自定义参数限制长度128
            orderRequest.setAttach(body);

            // 元转成分
            int totalFee = allPrice.multiply(new BigDecimal(100)).intValue();
            orderRequest.setTotalFee(totalFee);
            orderRequest.setSpbillCreateIp(IpUtil.getIpAddr(request));

            result = wxPayService.createOrder(orderRequest);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseUtil.fail(ORDER_PAY_FAIL, "订单不能支付");
        }

        for (LitemallOrder order : orders) {
            if (orderService.updateVersionSelective(order) == 0) {
                throw new RuntimeException("更新数据已失效");
            }
        }

        return ResponseUtil.ok(result);
    }

    /**
     * 微信付款成功或失败回调接口
     * <p>
     * 1. 检测当前订单是否是付款状态;
     * 2. 设置订单付款成功状态相关信息;
     * 3. 响应微信商户平台.
     *
     * @param request  请求内容
     * @param response 响应内容
     * @return 操作结果
     */
    public Object payNotify(HttpServletRequest request, HttpServletResponse response) {
        String xmlResult = null;
        try {
            xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
        } catch (IOException e) {
            e.printStackTrace();
            return WxPayNotifyResponse.fail(e.getMessage());
        }

        WxPayOrderNotifyResult result = null;
        try {
            result = wxPayService.parseOrderNotifyResult(xmlResult);

            if(!WxPayConstants.ResultCode.SUCCESS.equals(result.getResultCode())){
                logger.error(xmlResult);
                throw new WxPayException("微信通知支付失败！");
            }
            if(!WxPayConstants.ResultCode.SUCCESS.equals(result.getReturnCode())){
                logger.error(xmlResult);
                throw new WxPayException("微信通知支付失败！");
            }
        } catch (WxPayException e) {
            e.printStackTrace();
            return WxPayNotifyResponse.fail(e.getMessage());
        }

        logger.info("处理腾讯支付平台的订单支付");
        logger.info(result);

        //获取自定义参数
        List<Integer> orderIds = JacksonUtil.parseIntegerList(result.getAttach(), "orderIds");
        if (orderIds == null || orderIds.size() <= 0){
            return WxPayNotifyResponse.fail("自定义参数异常");
        }

        //订单总支付金额
        BigDecimal allPrice = new BigDecimal(0);
        //保存验证后的订单
        ArrayList<LitemallOrder> orders = new ArrayList<>();
        //判断所有订单id是否正常并保存订单信息
        for (Integer orderId : orderIds) {
            //查询订单
            LitemallOrder order = orderService.findById(orderId);
            if (order == null) {
                return WxPayNotifyResponse.fail("订单不存在 =" + orderId);
            }

            // 检查这个订单是否已经处理过
            if (order.getActualPrice().compareTo(BigDecimal.ZERO) != 0 && OrderConstant.hasPayed(order)) {
                return WxPayNotifyResponse.success("订单已经处理成功!");
            }

            orders.add(order);
            //订单金额相加得订单总支付金额
            allPrice = allPrice.add(order.getActualPrice());
        }

        // 分转化成元
        String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());
        // 检查支付订单金额
        if (!totalFee.equals(allPrice.toString())) {
            return WxPayNotifyResponse.fail(result.getAttach() + " : 支付金额不符合 totalFee=" + totalFee);
        }

        //更新订单信息
        for (LitemallOrder order : orders) {
            //添加支付信息
            order.setOrderPrice(allPrice);
            order.setPayTime(LocalDateTime.now());
            order.setPayId(result.getTransactionId());
            order.setOrderStatus(OrderConstant.STATUS_PAY);
            if (orderService.updateVersionSelective(order) <= 0) {
                throw new RuntimeException("更新数据已失效");
            }

            //有赏金更新赏金
            LitemallReward reward = rewardService.findByOrderId(order.getId());
            if (reward != null){
                wxRewardService.updateRewardStatus(reward);
            }

            //  支付成功，有团购信息，更新团购信息
            LitemallGroupon groupon = grouponService.queryByOrderId(order.getId());
            if (groupon != null) {
                orderCoreService.updateGrouponStatus(groupon);
            }else {
                //给商家发送通知
                notifyCoreService.orderNotify(order);
            }
            // 取消订单超时未支付任务
            taskService.removeTask(new OrderUnpaidTask(order.getId()));
        }

        return WxPayNotifyResponse.success("处理成功!");
    }

    /**
     * 取消订单
     * <p>
     * 1. 检测当前订单是否能够取消；
     * 2. 设置订单取消状态；
     * 3. 商品货品库存恢复；
     * 4. 返还优惠券；
     *
     * @param userId 用户ID
     * @param body   订单信息，{ orderId：xxx }
     * @return 取消订单操作结果
     */
    public Object cancel(Integer userId, String body) {
        if (Objects.isNull(userId)) {
            return ResponseUtil.unlogin();
        }
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        if (orderId == null) {
            return ResponseUtil.badArgument();
        }
        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            return ResponseUtil.badArgumentValue();
        }
        if (!order.getUserId().equals(userId)) {
            return ResponseUtil.badArgumentValue();
        }

        // 检测是否能够取消
        OrderHandleOption handleOption = OrderConstant.build(order);
        if (!handleOption.isCancel()) {
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "订单不能取消");
        }

        // 设置订单已取消状态
        order.setOrderStatus(OrderConstant.STATUS_CANCEL);
        if (orderService.updateVersionSelective(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        // 返还订单
        orderCoreService.orderRelease(order);
        return ResponseUtil.ok();
    }

    /**
     * 订单申请退款
     * <p>
     * 1. 检测当前订单是否能够退款；
     * 2. 设置订单申请退款状态。
     *
     * @param userId 用户ID
     * @param body   订单信息，{ orderId：xxx }
     * @return 订单退款操作结果
     */
    public Object refund(Integer userId, String body) {
        if (Objects.isNull(userId)) {
            return ResponseUtil.unlogin();
        }
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");

        if (orderId == null) {
            return ResponseUtil.badArgument();
        }

        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }

        if (!order.getUserId().equals(userId)) {
            return ResponseUtil.badArgumentValue();
        }

        if(order.getPayId() == null){
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "申请失败");
        }

        OrderHandleOption handleOption = OrderConstant.build(order);
        if (!handleOption.isRefund()) {
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "订单不能取消");
        }

        // 设置订单申请退款状态
        order.setOrderStatus(OrderConstant.STATUS_REFUND);
        if (orderService.updateVersionSelective(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        //给商家发送通知
        notifyCoreService.orderRefundNotify(order);

        return ResponseUtil.ok();
    }

    /**
     * 确认收货
     * <p>
     * 1. 检测当前订单是否能够确认收货；
     * 2. 设置订单确认收货状态。
     *
     * @param userId 用户ID
     * @param body   订单信息，{ orderId：xxx }
     * @return 订单操作结果
     */
    public Object confirm(Integer userId, String body , HttpServletRequest request) {
        if (Objects.isNull(userId)) return ResponseUtil.unlogin();
        
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        if (orderId == null) return ResponseUtil.badArgument();
        
        //获取订单
        LitemallOrder order = orderService.findById(userId, orderId);
        
        //判断订单是否存在
        if (Objects.isNull(order)) return ResponseUtil.badArgument();
        
        //判断订单是否属于当前用户
        if (!order.getUserId().equals(userId)) return ResponseUtil.badArgumentValue();
        
        //判断订单状态
        OrderHandleOption handleOption = OrderConstant.build(order);
        if (!handleOption.isConfirm() || !OrderConstant.isShipStatus(order)) {
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "订单不能确认收货");
        }
        
        //获取商品信息
        LitemallOrderGoods orderGoods = orderGoodsService.getByOrderId(orderId);
        if (Objects.isNull(orderGoods)){
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "商品不存在");
        }
        
        //获取店铺信息
        LitemallBrand brand = brandService.findById(order.getBrandId());
        if (Objects.isNull(brand)){
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "店铺信息获取失败");
        }

        //更新订单
        Short comments = orderGoodsService.getComments(orderId);
        order.setComments(comments);
        order.setOrderStatus(OrderConstant.STATUS_CONFIRM);
        order.setConfirmTime(LocalDateTime.now());
        if (orderService.updateVersionSelective(order) == 0) {
            throw new RuntimeException("订单数据失效");
        }

        //删除确认收货定时任务
        taskService.removeTask(new OrderUnconfirmedTask(orderId));

        //添加评论超时定时任务
        taskService.addTask(new OrderCommentTask(orderId));

        return ResponseUtil.ok();
    }

    /**
     * 删除订单
     * <p>
     * 1. 检测当前订单是否可以删除；
     * 2. 删除订单。
     *
     * @param userId 用户ID
     * @param body   订单信息，{ orderId：xxx }
     * @return 订单操作结果
     */
    public Object delete(Integer userId, String body) {
        if (Objects.isNull(userId)) {
            return ResponseUtil.unlogin();
        }
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        if (orderId == null) {
            return ResponseUtil.badArgument();
        }

        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }
        if (!order.getUserId().equals(userId)) {
            return ResponseUtil.badArgumentValue();
        }

        OrderHandleOption handleOption = OrderConstant.build(order);
        if (!handleOption.isDelete()) {
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "订单不能删除");
        }

        // 订单order_status没有字段用于标识删除
        // 而是存在专门的delete字段表示是否删除
        orderService.deleteById(orderId);
        // 售后也同时删除
        aftersaleService.deleteByOrderId(userId, orderId);

        return ResponseUtil.ok();
    }

    /**
     * 待评价订单商品信息
     *
     * @param userId  用户ID
     * @param ogId 订单商品ID
     * @return 待评价订单商品信息
     */
    public Object goods(Integer userId, Integer ogId) {
        if (Objects.isNull(userId)) {
            return ResponseUtil.unlogin();
        }
        LitemallOrderGoods orderGoods = orderGoodsService.findById(ogId);
        if (orderGoods != null) {
            Integer orderId = orderGoods.getOrderId();
            LitemallOrder order = orderService.findById(orderId);
            if (!order.getUserId().equals(userId)) {
                return ResponseUtil.badArgument();
            }
        }
        return ResponseUtil.ok(orderGoods);
    }

    /**
     * 评价订单商品
     * <p>
     * 确认商品收货或者系统自动确认商品收货后7天内可以评价，过期不能评价。
     *
     * @param userId 用户ID
     * @param body   订单信息，{ orderId：xxx }
     * @return 订单操作结果
     */
    public Object comment(Integer userId, String body) {
        if (Objects.isNull(userId)) {
            return ResponseUtil.unlogin();
        }

        Integer valueId = JacksonUtil.parseInteger(body, "valueId");
        if (valueId == null) {
            return ResponseUtil.badArgument();
        }
        LitemallOrderGoods orderGoods = orderGoodsService.findById(valueId);
        if (orderGoods == null) {
            return ResponseUtil.badArgumentValue();
        }
        Integer orderId = orderGoods.getOrderId();
        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            return ResponseUtil.badArgumentValue();
        }
        if (!OrderConstant.isConfirmStatus(order) && !OrderConstant.isAutoConfirmStatus(order)) {
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "当前商品不能评价");
        }
        if (!order.getUserId().equals(userId)) {
            return ResponseUtil.fail(ORDER_INVALID, "当前商品不属于用户");
        }
        Integer commentId = orderGoods.getComment();
        if (commentId == -1) {
            return ResponseUtil.fail(ORDER_COMMENT_EXPIRED, "当前商品评价时间已经过期");
        }
        if (commentId != 0) {
            return ResponseUtil.fail(ORDER_COMMENTED, "订单商品已评价");
        }

        String content = JacksonUtil.parseString(body, "content");
        Integer star = JacksonUtil.parseInteger(body, "star");
        if (star == null || star < 0 || star > 5) {
            return ResponseUtil.badArgumentValue();
        }
        Boolean hasPicture = JacksonUtil.parseBoolean(body, "hasPicture");
        List<String> picUrls = JacksonUtil.parseStringList(body, "picUrls");
        if (hasPicture == null || !hasPicture) {
            picUrls = new ArrayList<>(0);
        }

        // 1. 创建评价
        LitemallComment comment = new LitemallComment();
        comment.setUserId(userId);
        comment.setType((byte) 0);
        comment.setValueId(orderGoods.getGoodsId());
        comment.setStar(star.shortValue());
        comment.setContent(content);
        comment.setHasPicture(hasPicture);
        comment.setPicUrls(picUrls.toArray(new String[]{}));
        commentService.save(comment);

        // 2. 更新订单商品的评价列表
        orderGoods.setComment(comment.getId());
        if (orderGoodsService.updateVersionSelective(orderGoods) == 0){
            throw new RuntimeException("商品评论更新失败");
        }

        // 3. 更新订单中未评价的订单商品可评价数量
        Short commentCount = order.getComments();
        if (commentCount > 0) {
            commentCount--;
        }

        //判断是否还有待评论订单
        if (commentCount == 0){
            order.setOrderStatus(OrderConstant.STATUS_COMMENT);
        }

        order.setComments(commentCount);
        if (orderService.updateVersionSelective(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        return ResponseUtil.ok();
    }

    /**
     * 订单退款
     * <p>
     * 1. 检测当前订单是否能够退款;
     * 2. 微信退款操作;
     * 3. 设置订单退款确认状态；
     * 4. 订单商品库存回库。
     * <p>
     * TODO
     * 虽然接入了微信退款API，但是从安全角度考虑，建议开发者删除这里微信退款代码，采用以下两步走步骤：
     * 1. 管理员登录微信官方支付平台点击退款操作进行退款
     * 2. 管理员登录litemall管理后台点击退款操作进行订单状态修改和商品库存回库
     *
     * @param body 订单信息，{ orderId：xxx }
     * @return 订单退款操作结果
     */
    public Object adminRefund(String body) {
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        String refundMoney = JacksonUtil.parseString(body, "refundMoney");
        if (orderId == null) {
            return ResponseUtil.badArgument();
        }
        if (Objects.isNull(refundMoney)) {
            return ResponseUtil.badArgument();
        }

        LitemallOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }

        if (order.getActualPrice().compareTo(new BigDecimal(refundMoney)) != 0) {
            return ResponseUtil.badArgumentValue();
        }

        // 如果订单不是退款状态，则不能退款
        if (!(OrderConstant.isRefundStatus(order) || OrderConstant.isGrouponFailStatus(order))){
            return ResponseUtil.fail(ORDER_INVALID, "订单不是退款状态，不能退款");
        }

        //如果订单金额为零则跳过退款接口直接修改订单状态
        if (new BigDecimal(refundMoney).compareTo(BigDecimal.ZERO) != 0) {
            // 微信退款
            WxPayRefundResult refundResult = payCoreService.wxPayRefund(order);
            order.setRefundContent(refundResult.getRefundId());
        }else {
            order.setRefundContent(order.getOrderSn());
        }


        // 设置订单取消状态
        LocalDateTime now = LocalDateTime.now();
        order.setRefundTime(now);
        order.setRefundType("微信退款接口");
        order.setRefundAmount(order.getActualPrice());
        order.setOrderStatus(OrderConstant.STATUS_REFUND_CONFIRM);
        if (orderService.updateVersionSelective(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        // 返还订单
        orderCoreService.orderRelease(order);

        //订单退款订阅通知
        LitemallUser user = userService.findById(order.getUserId());
        subscribeMessageService.refundSubscribe(user.getWeixinOpenid(),order);

        return ResponseUtil.ok();
    }

    /**
     * 发货
     * 1. 检测当前订单是否能够发货
     * 2. 设置订单发货状态
     *
     * @param body 订单信息，{ orderId：xxx, shipSn: xxx, shipChannel: xxx }
     * @return 订单操作结果
     * 成功则 { errno: 0, errmsg: '成功' }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    public Object adminShip(String body) {
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        String shipSn = JacksonUtil.parseString(body, "shipSn");
        String shipChannel = JacksonUtil.parseString(body, "shipChannel");
        if (orderId == null || shipSn == null || shipChannel == null) {
            return ResponseUtil.badArgument();
        }

        LitemallOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }

        // 如果订单不是已付款状态，则不能发货
        if(!(OrderConstant.isPayStatus(order) || OrderConstant.isBtlPayStatus(order) || OrderConstant.isGrouponSucceedStatus(order))){
            return ResponseUtil.fail(ORDER_UNKNOWN, "订单不能发货");
        }

        order.setOrderStatus(OrderConstant.STATUS_SHIP);
        order.setShipSn(shipSn);
        order.setShipChannel(shipChannel);
        order.setShipTime(LocalDateTime.now());
        if (orderService.updateVersionSelective(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        //订单发货订阅通知
        LitemallUser user = userService.findById(order.getUserId());
        subscribeMessageService.shipSubscribe(user.getWeixinOpenid(),order);

        //添加确认收货定时任务
        taskService.addTask(new OrderUnconfirmedTask(orderId));

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 发货会发送通知短信给用户:          *
        // "您的订单已经发货，快递公司 {1}，快递单 {2} ，请注意查收"
        notifyService.notifySmsTemplate(order.getMobile(), NotifyType.SHIP, new String[]{shipChannel, shipSn});

        return ResponseUtil.ok();
    }
}